home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene Storm
/
Scene Storm - Volume 1.iso
/
coding
/
c
/
nullmodem
/
src
/
modem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-18
|
15KB
|
515 lines
#include "defs.h"
#include "protos.h"
#define MSG_OK 0
#define MSG_CONNECT 1
#define MSG_RING 2
#define MSG_NO_CARRIER 3
#define MSG_ERROR 4
#define MSG_BUSY 5
char *speed[] = {
"",
" 103",
" V21",
" 300",
" 1200",
" 2400",
" 4800",
" 7200",
" 9600",
" 12000",
" 14400",
" 16800",
" 19200",
};
char *protocol[] = {
"",
"/NONE",
"/SYNC",
"/REL",
"/REL-MNP",
"/REL-MNP-COMP",
"/REL-LAPM",
"/REL-LAPM-COMP",
"/V32",
"/ARQ",
"/ARQ/HST",
"/ARQ/HST/HST/V42BIS",
"/ARQ/HST/HST/MNP5",
"/ARQ/V32",
"/ARQ/V32/LAPM/V42BIS",
"/ARQ/V32/LAPM/MNP",
"/ARQ/V32/LAPM/MNP5",
"/ARQ/LAPM/V42BIS",
"/V42BIS",
};
UBYTE S_Default[64] = {
0, 0, 020, 2, 012, 010, 0, 011,
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, STATE_COMMAND,
};
/*
* I am the Task. (Process, actually..)
*/
void
modem_task(void)
{
struct NullModem *modem = FindTask(NULL)->tc_UserData;
struct MsgPort *tport = &modem->nm_TimePort;
struct timerequest *tr = &modem->nm_Timerequest;
struct NullUnit *u0 = modem->nm_Unit[0];
struct NullUnit *u1 = modem->nm_Unit[1];
/* load the default S Register values */
S_Restore(modem->nm_Unit[0],1);
S_Restore(modem->nm_Unit[1],1);
/* Initialise the timer port */
tport->mp_Node.ln_Type = NT_MSGPORT;
tport->mp_Flags = PA_SIGNAL;
tport->mp_SigBit = SIGBREAKB_CTRL_F;
tport->mp_SigTask = modem->nm_Taskptr;
NewList(&tport->mp_MsgList);
/* Initialiase the timer request */
tr->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
tr->tr_node.io_Message.mn_ReplyPort = tport;
tr->tr_node.io_Command = TR_ADDREQUEST;
/* start the 1s timer */
tr->tr_time.tv_secs = 1;
tr->tr_time.tv_micro = 0;
SendIO((struct IORequest *)tr);
for(;;) {
ULONG mask = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F );
ObtainSemaphore(&modem->nm_Semaphore);
if( mask & SIGBREAKF_CTRL_E ) break; /* Exit */
if( mask & SIGBREAKF_CTRL_D ) { /* Drop DTR */
if( u0->u_OpenCnt && u0->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
dprintf(u0, 2, "Disconnected\n");
put_msg(u0, MSG_NO_CARRIER);
u0->u_SReg[SREG_STATE] = STATE_COMMAND;
u0->u_SReg[SREG_CMD_COUNT] = 0;
}
if( u1->u_OpenCnt && u1->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
dprintf(u1, 2, "Disconnected\n");
put_msg(u1, MSG_NO_CARRIER);
u1->u_SReg[SREG_STATE] = STATE_COMMAND;
u1->u_SReg[SREG_CMD_COUNT] = 0;
}
}
if( mask & SIGBREAKF_CTRL_F ) { /* Timer events */
GetMsg(tport);
do_timer(u0,u1);
do_timer(u1,u0);
tr->tr_time.tv_secs = 1;
tr->tr_time.tv_micro = 0;
SendIO((struct IORequest *)tr);
}
if( mask & SIGBREAKF_CTRL_C ) { /* Copy Data */
copy_data(u0, u1);
copy_data(u1, u0);
}
ReleaseSemaphore(&modem->nm_Semaphore);
}
AbortIO((struct IORequest *)tr);
WaitIO((struct IORequest *)tr);
CloseDevice((struct IORequest *)&modem->nm_Timerequest);
Forbid(); /* release memory/device etc */
DevBase->b_Lib.lib_OpenCnt--;
FreeMem(u0, sizeof(struct NullUnit));
FreeMem(u1, sizeof(struct NullUnit));
FreeMem(modem, sizeof(struct NullModem));
/* fall off the end.. byebye! */
}
/*
* put_char() copies 1 char to a unit's buffer or readqueue
*
* returns TRUE for success/FALSE for fail (buffer full)
*/
int
put_char(struct NullUnit *unit, char c)
{
struct IOExtSer *iob = unit->u_Readlist.mlh_Head;
/*
* copy to any pending reads, else to the buffer
*/
if( iob->IOSer.io_Message.mn_Node.ln_Succ ) {
((UBYTE *)iob->IOSer.io_Data)[iob->IOSer.io_Actual++] = c;
if( iob->IOSer.io_Length == iob->IOSer.io_Actual ) {
Remove(&iob->IOSer.io_Message.mn_Node);
ReplyMsg(&iob->IOSer.io_Message);
dprintf(unit, 2, "read (%ld) complete\n",iob->IOSer.io_Length);
}
}
else if( unit->u_Bufcount < UNIT_BUF_SIZE ) {
unit->u_Bufcount++;
*unit->u_Writeptr-- = c;
if( unit->u_Writeptr < unit->u_Buffer )
unit->u_Writeptr += UNIT_BUF_SIZE;
}
else
return(FALSE);
return(TRUE);
}
/*
* puts a message string to the modem unit
*/
void
put_str(struct NullUnit *unit, char *ptr)
{
while( *ptr && put_char(unit, *ptr) ) ptr++;
}
void
put_msg(struct NullUnit *unit, int num)
{
if( unit->u_SReg[SREG_NUMERIC] ) {
put_char(unit, '\r');
put_char(unit, '0' + num); /* limited to 10 result codes */
put_char(unit, '\r');
}
else {
put_str(unit, "\r\n");
switch( num ) {
case MSG_OK:
put_str(unit, "OK");
break;
case MSG_CONNECT:
put_str(unit, "CONNECT");
put_str(unit, speed[unit->u_SReg[SREG_SPEED] >= (sizeof(speed)/sizeof(*speed)) ? 0 : unit->u_SReg[SREG_SPEED]]);
put_str(unit, protocol[unit->u_SReg[SREG_PROTOCOL] >= (sizeof(protocol)/sizeof(*protocol)) ? 0 : unit->u_SReg[SREG_PROTOCOL]]);
break;
case MSG_RING:
put_str(unit, "RING");
break;
case MSG_NO_CARRIER:
put_str(unit, "NO CARRIER");
break;
case MSG_ERROR:
put_str(unit, "ERROR");
break;
case MSG_BUSY:
put_str(unit, "BUSY");
break;
}
put_str(unit, "\r\n");
}
}
void
do_command(struct NullUnit *unit)
{
char *p = unit->u_Command;
int count = unit->u_SReg[SREG_CMD_COUNT];
unit->u_SReg[SREG_CMD_COUNT] = 0;
if( count-- && (*p == 'A' || *p == 'a') ) {
p++;
if( count-- && (*p == 'T' || *p == 't') ) {
p++;
while( count-- ) {
switch(*p++) {
case 'a':
case 'A':
unit->u_SReg[SREG_STATE] = STATE_ANSWERING;
unit->u_SReg[SREG_ANSWERING] = unit->u_SReg[SREG_DELAY];
unit->u_SReg[SREG_RINGS] = 0;
return;
case 'd':
case 'D':
unit->u_SReg[SREG_STATE] = STATE_DIALING;
unit->u_SReg[SREG_RINGS] = unit->u_SReg[SREG_TIMEOUT];
unit->u_SReg[SREG_ANSWERING] = 0;
return;
case 'z':
case 'Z':
S_Restore(unit,1);
break;
case 'f':
case 'F':
S_Restore(unit,0);
break;
case 'w':
case 'W':
S_Save(unit);
break;
case 'l':
case 'L':
{
extern char ID[];
UBYTE i = 0;
put_str(unit, "\r\n");
put_str(unit, ID);
while( i < 8 ) {
UBYTE j = 0;
while( j < 8 ) {
UBYTE s = unit->u_SReg[(i << 3) + j];
put_char(unit,i+'0');
put_char(unit,j+'0');
put_char(unit,':');
put_char(unit,((s >> 6) & 0x7) + '0');
put_char(unit,((s >> 3) & 0x7) + '0');
put_char(unit,((s >> 0) & 0x7) + '0');
put_char(unit,' ');
put_char(unit,' ');
j++;
}
put_char(unit,'\r');
put_char(unit,'\n');
i++;
}
}
break;
case 's':
case 'S':
{
int reg = 0, value = 0;
while( count && *p >= '0' && *p <= '7' ) {
reg = (reg << 3) + (*p - '0');
p++, count--;
}
if( count && *p == '=' ) p++,count--;
else {
put_msg(unit, MSG_ERROR);
return;
}
while( count && *p >= '0' && *p <= '7' ) {
value = (value << 3) + (*p - '0');
p++, count--;
}
unit->u_SReg[reg & 0x3f] = value & 0xff;
}
break;
default:
put_msg(unit, MSG_ERROR);
return;
}
}
put_msg(unit, MSG_OK);
}
}
}
/*
* copy_data() processes writes that may be waiting at the unit
*
* arguments: unit is the unit to process from
* other is the unit to write to, if connected
*/
void
copy_data(struct NullUnit *unit, struct NullUnit *other)
{
struct IOExtSer *temp, *iob = unit->u_Writelist.mlh_Head;
/*
* for each write request in the queue..
*/
while( temp = iob->IOSer.io_Message.mn_Node.ln_Succ ) {
UBYTE *data = (UBYTE *)iob->IOSer.io_Data + iob->IOSer.io_Actual;
unsigned int count = iob->IOSer.io_Length - iob->IOSer.io_Actual;
/*
* copy the data from this write request to the writeunit
*/
if( unit->u_SReg[SREG_STATE] == STATE_CONNECTED ) {
while( count ) {
if( !put_char(other, *data) ) break;
count--;
data++;
}
}
else { /* or else do local command line stuff */
while( count ) {
if( unit->u_SReg[SREG_STATE] != STATE_COMMAND ) {
if( *data != '\n' ) {
unit->u_SReg[SREG_STATE] = STATE_COMMAND;
unit->u_SReg[SREG_CMD_COUNT] = 0;
put_msg(unit, MSG_NO_CARRIER);
}
}
if( unit->u_SReg[SREG_LOCALECHO] && !put_char(unit, *data) ) break;
if( unit->u_SReg[SREG_STATE] == STATE_COMMAND ) {
if( *data != '\n' ) {
if( *data == unit->u_SReg[SREG_BACKSPACE] ) {
if( unit->u_SReg[SREG_CMD_COUNT] )
unit->u_SReg[SREG_CMD_COUNT] -= 1;
}
else if( *data != '\r' ) {
if( unit->u_SReg[SREG_CMD_COUNT] < 256 ) {
unit->u_Command[unit->u_SReg[SREG_CMD_COUNT]] = *data;
unit->u_SReg[SREG_CMD_COUNT]++;
}
}
else
do_command(unit);
}
}
count--;
data++;
}
}
iob->IOSer.io_Actual = iob->IOSer.io_Length - count;
if( count ) break; /* no point continuing if there was no room */
/*
* Request satisfied, go on to the next one..
*/
Remove(&iob->IOSer.io_Message.mn_Node);
ReplyMsg(&iob->IOSer.io_Message);
dprintf(unit, 3, "write (%ld) complete\n",iob->IOSer.io_Length);
iob = temp;
}
}
void
do_connect(struct NullUnit *u0, struct NullUnit *u1)
{
u0->u_SReg[SREG_STATE] = STATE_CONNECTED;
put_msg(u0, MSG_CONNECT);
u1->u_SReg[SREG_STATE] = STATE_CONNECTED;
put_msg(u1, MSG_CONNECT);
}
/* Ugh -- Clean Me Up! */
void
do_timer(struct NullUnit *unit, struct NullUnit *other)
{
if( unit->u_SReg[SREG_STATE] == STATE_DIALING ) {
if( unit->u_SReg[SREG_RINGS] ) {
if( other->u_OpenCnt ) {
if( other->u_SReg[SREG_STATE] == STATE_ANSWERING ) {
if( other->u_SReg[SREG_ANSWERING] == 0 ) {
do_connect(unit,other);
}
}
else {
unit->u_SReg[SREG_RINGS] -= 1;
if( (unit->u_SReg[SREG_TIMEOUT] - unit->u_SReg[SREG_RINGS]) == other->u_SReg[SREG_ANSWER] ) {
do_connect(unit,other);
}
else {
put_msg(other, MSG_RING);
dprintf(other,2,"Ring\n");
}
}
}
else {
put_msg(unit, MSG_BUSY);
unit->u_SReg[SREG_RINGS] = 0;
unit->u_SReg[SREG_STATE] = STATE_COMMAND;
}
}
else {
put_msg(unit, MSG_NO_CARRIER);
unit->u_SReg[SREG_STATE] = STATE_COMMAND;
}
}
else if( unit->u_SReg[SREG_STATE] == STATE_ANSWERING ) {
if( unit->u_SReg[SREG_ANSWERING] == 0 ) {
put_msg(unit, MSG_NO_CARRIER);
unit->u_SReg[SREG_STATE] = STATE_COMMAND;
}
else {
unit->u_SReg[SREG_ANSWERING] -= 1;
}
}
}
/*
* Save/Restore the S Registers from ENV:nullmodemX.config
* X is unit number
*/
const UBYTE vputch[] = { 0x16, 0xc0, 0x4e, 0x75 }; /* move.b d0,(a3)+ rts */
char *varname(UWORD unitnum)
{
static char buffer[32];
RawDoFmt("nullmodem%d.config",&unitnum,(void (*)())vputch,buffer);
return(buffer);
}
S_Restore(struct NullUnit *unit, int load)
{
UBYTE Temp[65];
LONG len = 0;
if( load ) {
struct Library *DOSBase;
if( DOSBase = OpenLibrary("dos.library",36) ) {
len = GetVar(varname(unit->u_Unitnum), Temp, 65, GVF_BINARY_VAR);
CloseLibrary(DOSBase);
}
}
if( len == 64 ) {
int i;
for( i = 0 ; i < 64 ; i++ ) unit->u_SReg[i] = Temp[i];
}
else {
int i;
for( i = 0 ; i < 64 ; i++ ) unit->u_SReg[i] = S_Default[i];
}
}
S_Save(struct NullUnit *unit)
{
struct Library *DOSBase = OpenLibrary("dos.library",36);
if( DOSBase ) {
SetVar(varname(unit->u_Unitnum), unit->u_SReg, 64, GVF_GLOBAL_ONLY);
CloseLibrary(DOSBase);
}
}